﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;

namespace Runtime.Services.Battle.StateMachine {

    /// <summary>
    /// 战斗实体状态机
    /// </summary>
    public interface IDFR_BattleEntityStateMachine {

        /// <summary>
        /// 状态
        /// </summary>
        DFR_BattleEntityState State { get; set; }

        /// <summary>
        /// 是否已经初始化
        /// </summary>
        bool IsInitialized { get; }

        /// <summary>
        /// 播放
        /// </summary>
        /// <param name="speed">播放速度</param>
        void Play(float speed);
    }

    internal abstract class DFR_BattleEntityStateMachine : DFR_PoolObject, IDFR_BattleEntityStateMachine {

        protected static readonly ObjectPool<IParticleReferences> m_ParticleReferencesPool = new(() => new ParticleReferences(), actionOnRelease: item => (item as ParticleReferences).Release(), maxSize: 1024 * 1024, collectionCheck: false);

        public interface IParticleReferences {
            List<ParticleSystem> ParticleSystemList { get; }
            Dictionary<ParticleSystem, ParticleSystemRenderer> ParticleSystemRendererDictionary { get; }
        }

        private class ParticleReferences : IParticleReferences {

            public List<ParticleSystem> ParticleSystemList { get; } = new();
            public Dictionary<ParticleSystem, ParticleSystemRenderer> ParticleSystemRendererDictionary { get; } = new();

            public void Release() {
                ParticleSystemList.Clear();
                ParticleSystemRendererDictionary.Clear();
            }
        }

        public DFR_BattleEntityState State { get; set; }

        public abstract bool IsInitialized { get; }

        public abstract void Play(float speed);

        protected override void Allocate() {
        }

        protected bool ReleaseParticle(IParticleReferences particleReferences) {
            if (particleReferences != null) {
                foreach (var particleSystem in particleReferences.ParticleSystemList) {
                    if (particleSystem.isPlaying && particleReferences.ParticleSystemRendererDictionary.TryGetValue(particleSystem, out var particleSystemRenderer) && particleSystemRenderer != null && particleSystemRenderer.enabled) {
                        particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmitting);
                    }
                }
                m_ParticleReferencesPool.Release(particleReferences);
                return true;
            }
            return false;
        }

        protected void ProcessParticle(bool isStateChanged, float speed, GameObject gameObject, ref IParticleReferences particleReferences) {
            if (particleReferences == null) {
                particleReferences = m_ParticleReferencesPool.Get();
                gameObject.GetComponentsInChildren(true, particleReferences.ParticleSystemList);
            }
            if (particleReferences.ParticleSystemList.Count > 0) {
                foreach (var particleSystem in particleReferences.ParticleSystemList) {
                    if (!particleReferences.ParticleSystemRendererDictionary.TryGetValue(particleSystem, out var particleSystemRenderer)) {
                        particleReferences.ParticleSystemRendererDictionary[particleSystem] = particleSystemRenderer = particleSystem.GetComponent<ParticleSystemRenderer>();
                        if (particleSystemRenderer == null || !particleSystemRenderer.enabled) {
                            particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmitting);
                            continue;
                        }
                    } else if (particleSystemRenderer == null || !particleSystemRenderer.enabled) {
                        continue;
                    }
                    if (isStateChanged) {
                        particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmitting);
                        particleSystem.Play(true);
                    }
                    var mainModule = particleSystem.main;
                    mainModule.simulationSpeed = speed;
                }
            }
        }
    }
}
